package com.biscuit.page.basicservice.service;

import com.biscuit.page.basicservice.api.model.request.common.CommonCheckVerifyCodeAReq;
import com.biscuit.page.basicservice.api.model.request.common.CommonGetVerifyCodeAReq;
import com.biscuit.page.basicservice.bean.RedisCache;
import com.biscuit.page.basicservice.conf.handler.RequestContextHandler;
import com.biscuit.page.basicservice.design.verify_code.publish.VerifyCodePublishContext;
import com.biscuit.page.basicservice.design.verify_code.publish.VerifyCodePublishTypeEnum;
import com.biscuit.page.basicservice.design.verify_code.publish.factory.VerifyCodePublishStrategyFactory;
import com.biscuit.page.basicservice.model.dto.common.VerifyCodePublishDTO;
import com.biscuit.page.basicservice.model.enums.VerifyCodeWorkTypeEnum;
import com.biscuit.page.basicservice.utils.BaseExceptionUtil;
import com.biscuit.page.basicservice.utils.VerifyCodeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author mazihao
 * @createTime 2024/3/23 14:03
 */
@Slf4j
@Service
public class CommonService {

    @Resource
    private RedisCache redisCache;

    @Resource
    private VerifyCodePublishStrategyFactory verifyCodePublishStrategyFactory;

    public void verifyCodePublish(VerifyCodePublishDTO dto) {
        VerifyCodePublishContext context = new VerifyCodePublishContext();
        context.setAccount(dto.getAccount());
        context.setPrefix(dto.getWorkTypeEnum().getPrefix());
        context.setIp(RequestContextHandler.getContext().getIp());
        this.verifyCodePublishStrategyFactory.create(dto.getPublishTypeEnum().getType()).publish(context);
    }

    public void getVerifyCode(CommonGetVerifyCodeAReq req) {
        // 获取验证码业务类型枚举
        VerifyCodeWorkTypeEnum workTypeEnum = VerifyCodeWorkTypeEnum.getEnumByType(req.getWorkType());

        // 根据发送账号获取验证码发送类型
        VerifyCodePublishTypeEnum publishTypeEnum = VerifyCodePublishTypeEnum.getEnumByAccount(req.getTarget());

        // 类型校验
        BaseExceptionUtil.throwException(Objects.nonNull(workTypeEnum) && Objects.nonNull(publishTypeEnum), "验证码类型不存在");

        // 发送验证码
        VerifyCodePublishDTO dto = new VerifyCodePublishDTO();
        dto.setAccount(req.getTarget());
        dto.setWorkTypeEnum(workTypeEnum);
        dto.setPublishTypeEnum(publishTypeEnum);
        this.verifyCodePublish(dto);
    }

    public void checkVerifyCode(Integer workCode, String account, String verifyCode) {
        CommonCheckVerifyCodeAReq req = new CommonCheckVerifyCodeAReq();
        req.setWorkType(workCode);
        req.setTarget(account);
        req.setVerifyCode(verifyCode);
        this.checkVerifyCode(req);
    }

    public void checkVerifyCode(CommonCheckVerifyCodeAReq req) {
        // 获取验证码发送业务类型对应枚举
        VerifyCodeWorkTypeEnum workTypeEnum = VerifyCodeWorkTypeEnum.getEnumByType(req.getWorkType());

        // 验证码业务类型校验
        BaseExceptionUtil.throwException(Objects.nonNull(workTypeEnum), "验证码业务类型不存在");

        // 组装验证码缓存 key
        String verifyCodeKey = VerifyCodeUtil.getVerifyCodeKey(workTypeEnum.getPrefix(), req.getTarget());

        // 从缓存中获取验证码
        String verifyCode = this.redisCache.get2String(verifyCodeKey);

        // 过期校验
        BaseExceptionUtil.throwException(StringUtils.isNotBlank(verifyCode), "验证码已过期");

        // 正确校验
        BaseExceptionUtil.throwException(verifyCode.equals(req.getVerifyCode()), "验证码错误");

        // 校验通过，删除缓存中的验证码
        this.redisCache.delete(verifyCodeKey);
    }

}
